#include "../PreCompile.hpp"
#include "Package.hpp"

namespace BuildNG
{
  VCPackage::PackageCache VCPackage::package_cache;

  Glib::RefPtr<VCPackage> VCPackage::get_package(const Glib::ustring &pkg_name,
    const Glib::ustring &configuration_name)
  {
    std::vector<Glib::ustring> dep_chain;
    return get_package(pkg_name,configuration_name,dep_chain);
  }
  
  Glib::RefPtr<VCPackage> VCPackage::get_package(const Glib::ustring &pkg_name,
    const Glib::ustring &configuration_name,std::vector<Glib::ustring> &dep_chain)
  {
    for(int i = 0;i < (int)dep_chain.size();i++)
    {
      if(dep_chain[i] == pkg_name)
      {
        throw Exception("Package \"" + pkg_name + "\" has a circular dependency on itself, which is not allowed.");
      }
    }

    PackageKey key;
    key.name = pkg_name;
    key.configuration_name = configuration_name;
    PackageCacheIt it = package_cache.find(key);
    if(it != package_cache.end())
    {
      Glib::RefPtr<VCPackage> ret = it->second.acquire();
      if(ret)
        return ret;
    }

    // couldn't be found, so we have to load it.
    Glib::RefPtr<VCPackage> pkg(new VCPackage(pkg_name,configuration_name,dep_chain));
    package_cache.insert(std::make_pair(key,pkg));
    return pkg;
  }

  static void remove_newlines(Glib::ustring &str)
  {
    for(gchar *c = (gchar*)str.c_str();*c;c++)
    {
      if(*c == '\n' || *c == '\r')
        *c = ' ';
    }
  }

  VCPackage::VCPackage(const Glib::ustring &pkg_name,const Glib::ustring &configuration_name,
    std::vector<Glib::ustring> &dep_chain)
  {
    Glib::ustring pkg_path = Settings::get_setting_path("/buildng-settings/vc-compiler-settings/pkg-path");
    Glib::ustring pkg_file_name = Glib::build_filename(pkg_path,pkg_name + ".xml");
    if(!Glib::file_test(pkg_file_name,Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR))
    {
      throw Exception("Package \"" + pkg_name + "\" not found.");
    }

    SettingsFile pkg_file(pkg_file_name);

    if(!pkg_file.try_get_setting_string("/package/configuration[@name = '" + configuration_name + "']/cflags",cflags))
    {
      pkg_file.try_get_setting_string("/package/cflags",cflags);
    }
    remove_newlines(cflags);

    if(!pkg_file.try_get_setting_string("/package/configuration[@name = '" + configuration_name + "']/linker-cflags",linker_flags))
    {
      pkg_file.try_get_setting_string("/package/linker-flags",linker_flags);
    }
    remove_newlines(linker_flags);

    // load the dependencies
    std::vector<Glib::ustring> dependency_names;
    if(!pkg_file.try_get_setting_strarr("/package/configuration[@name = '" + configuration_name + "']/dependencies/package/@name",dependency_names))
    {
      pkg_file.try_get_setting_strarr("/package/dependencies/package/@name",dependency_names);
    }

    dep_chain.push_back(pkg_name);

    dependencies.reserve(dependency_names.size());
    for(int i = 0;i < (int)dependency_names.size();i++)
    {
      dependencies.push_back(get_package(dependency_names[i],configuration_name,dep_chain));
    }

    dep_chain.pop_back();
  }

  void VCPackage::get_dependencies_recursive(VCPackageSet &dest)
  {
    for(int i = 0;i < (int)dependencies.size();i++)
    {
      dest.insert(dependencies[i]);
      dependencies[i]->get_dependencies_recursive(dest);
    }
  }
}
